# encoding=utf8
import requests

from sdktest_module.multiTest.driver import Driver
import datetime
from sdktest_module.utils.wda_util import *
from sdktest_module.utils.httpUtil import download_app
from sdktest_module.utils.decorators import async_func
STEP_TIME_OUT = 5 * 60
cmd_iproxy = "iproxy -u {device} {port_pc}:{port_device}"
cmd_wda_default = "xcodebuild {option} -project {xcodeproj} -scheme {scheme}"
option_showdest = "-showdestination"
option_test = "test {destination}"
param_destination = "-destination id={device}"
wda_device_port = 8100
local_url = "http://localhost:{port}"
WDA_BASE_PATH = '/Users/yyinc/WebDriverAgent/'
install_cmd= 'ideviceinstaller -u %s -i %s'
def check_null(origin_func):
    # @wrapper(origin_func) # 加上报错：UnboundLocalError: local variable 'wrapper' referenced before assignment
    def wrapper(self, *args, **kwargs):
        if not self.device_id:
            print("Warning: device_id is none， return!!!")
            return None
        return origin_func(self, *args, **kwargs)
    return wrapper


class IOSDriver(Driver):
    def __init__(self, device, bundle_id, role):
        self.iproxy_rpc_process = None
        self.iproxy_wda_process = None
        self.xcode_wda_process = None
        self.wda_client = None
        self.wda_session = None
        self.is_watcher_running = False
        self.is_cloud_device = device.is_cloud_device
        if self.is_cloud_device:
            self.rpc_ip = device.rpc.split(':')[0]
            self.rpc_port = int(device.rpc.split(':')[1])
            self.wda_url = device.wda_url
        else:
            self.rpc_ip = '127.0.0.1'
            self.rpc_port = device.client_port
            self.wda_ip = '127.0.0.1'
            self.wda_port = self.rpc_port + 1
            self.wda_url = 'http://127.0.0.1:'+str(self.wda_port)

        super().__init__(device, role, self.rpc_ip, self.rpc_port)
        self.bundle_id = bundle_id
        self.device_name = self.role + '(' + ')'

    def initialize(self):
        """
        初始化 1：iproxy; 2.处理弹窗
        """
        if self.is_cloud_device:
            #云真机，不需要iproxy和run wda
            pass
        else:
            #本地手机，iproxy,run wda
            self.xcode_wda_process = self._run_wda_test(self.device.device_id)
            #等待wda启动，暂时sleep，todo
            self.iproxy_rpc_process = self._run_iproxy(self.device.device_id, self.rpc_port, 9000)
            self.iproxy_wda_process = self._run_iproxy(self.device.device_id, self.wda_port)
        print('wda_url: ' + self.wda_url)
        self.wda_client = wda.Client(self.wda_url)

        assert self.wda_client.wait_ready(), 'WDA client创建失败'

    @async_func
    def _watch_alert(self):
        self.is_watcher_running = True
        while self.is_watcher_running:
            if self.wda_session:
                try:
                    if self.wda_session.alert.wait(timeout=2):
                        self.alert_dealing = True
                        try:
                            print(self.wda_session.alert.text)
                            self._handle_alert()
                        except Exception as e:
                            # 连接或者处理弹窗失败自动恢复,并防止销毁时异常
                            print("handle watcher exception")
                            print(e)
                            pass
                        self._alert_dealing = False
                except:
                    print('alert wait exception')
            time.sleep(1)

    def _handle_alert(self):
        text = self.wda_session.alert.text
        if text:
            if '允许录屏' in text:
                self.wda_session.alert.click("录屏")
            # elif TEXT_ALERT_CAMERA in text or TEXT_ALERT_MIC in text:
            #     self.accept_alert()
            else:
                self.accept_alert()

    def accept_alert(self):
        """可以直接用该方法处理的弹窗:相机,麦克风"""
        start_time = time.time()
        if self.wda_session.alert.wait(0.5):
            self.wda_session.alert.accept()
        print("accept alert elapsed {}s".format(
            time.time() - start_time
        ))

    def _run_wda_test(self, device):
        """为设备启动wda test"""
        cmd = cmd_wda_default.format(
            option=option_test.format(destination=param_destination.format(
                device=device
            )),
            xcodeproj=WDA_BASE_PATH + 'WebDriverAgent.xcodeproj',
            scheme='WebDriverAgentRunner'
        )
        p = subprocess.Popen(cmd, shell=True)
        return p

    # def _install_app(self, product_url):
    #     filename = os.path.basename(product_url)
    #     path = os.getcwd()
    #     downloadPath = os.path.join(path, 'download', self.device.device_id)
    #     if not os.path.exists(downloadPath):
    #         os.mkdir(downloadPath)
    #     filepath = os.path.join(downloadPath, filename)
    #     if download_app(product_url, filepath):
    #         # install
    #         print('install IOS App')
    #         cmd1 = install_cmd % (self.device.device_id, filepath)
    #         p = subprocess.Popen(cmd1.split())
    #         out, err = p.communicate()
    #         p.wait()
    #         return True
    #     else:
    #         return False
    @check_null
    def _run_iproxy(self, device, port_pc,port_device=8100):
        """启动iproxy将pc本机port映射对应设备端口"""
        cmd = cmd_iproxy.format(
            device=device, port_pc=port_pc, port_device=port_device
        )
        p = subprocess.Popen(cmd, shell=True)
        return p

    @check_null
    def stop_app(self):
        if not self.device_id:
            print('device is none')
            return

    @check_null
    def start_app(self):
        self._watch_alert()
        self.wda_session = self.wda_client.session(self.bundle_id, alert_action="accept")
        # launch without terminate app (WDAEmptyResponseError might raise)
        # self.wda_session.app_activate(self.bundle_id)  # same as app_launch


    def install_app(self, downLoadPath):
        # 判断是否为云真机
        if not self.is_cloud_device:
            return
        startTime = time.time()
        url = "http://" + self.rpc_ip + ":3600/app/install?udid="+self.device_id
        payload = {'url': downLoadPath}
        files = []
        headers = {'Authorization': 'Bearer c71521ea75614cc0bfd2a2d59667a40e'}

        retry = 3
        while retry > 0:
            response = requests.request("POST", url, headers=headers, data=payload, files=files)
            # print("APP install response:" + str(response.text.encode('utf8')))
            if response.json()["success"] == "false":
                print(self.role + "(" + self.device_id + ")" + ":App install fail,retry time:" + str(4 - retry))
                retry = retry - 1
            else:
                print(self.role + ":APP install success,cost time:" + str(format(time.time()-startTime, '.3f')) + "s")
                break

            if retry == 0:
                assert False, "App install failed"

    @check_null
    def finish(self):
        # 停止监控
        self.is_watcher_running = False
        self.tcpclient.disconnect()
        #停止app
        try:
            if self.wda_session:
                self.wda_session.app_terminate(self.bundle_id)
        except:
            print('wda app_terminate exception')
        finally:
            if not self.is_cloud_device:
                self.iproxy_wda_process.kill()
                self.iproxy_rpc_process.kill()
                self.xcode_wda_process.kill()


    def send_command(self, *cmds, wait_return=True, check_empty=True):
        print("[{}] {} send command:{}".format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'), self.device_name, cmds))
        if check_empty:
            self.callback_buf.check_empty()
        self.callback_buf.clear()
        self.return_buf.clear()
        if len(cmds) > 1:
            self.tcpclient.send_msg('[{}]'.format(','.join(list(cmds))).replace('\'', '"'))  # 多命令字符串转为json格式
        else:
            self.tcpclient.send_msg(str(cmds[0]).replace('\'', '"'))
        if wait_return:
            for cmd in cmds:
                dic = eval(cmd)
                self.return_buf.wait_return(dic['api'])
                # 检查是否有错误信息
                self.error_buf.constains_error()

    # def dataHandler(self, data):
    #     print("[{}] {} receiv server msg:{}".format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'), self.device_name, data))
    #     dics = json.loads(data)
    #     if dics['type'] == 'callback':
    #         self.callback_buf.store_callback(dics['key'], dics['value'])
    #     elif dics['type'] == 'return':
    #         self.return_buf.store_return(dics['key'], dics['value'])
    #     elif dics['type'] == 'error':
    #         assert False, dics['key'] + ':' + dics['value']
    #
    # def clear(self):
    #     """
    #     清理消息
    #     """
    #     self.callback_buf.clear()
    #     self.return_buf.clear()
